
SUB_INDENT = '    '
DATA_STRING_FORMAT = "0x{0:s}"
STRING_FORMAT = "{0:s}"
HEX_DATA_FORMAT = "0x{0:02X}"
DATA_FORMAT = "{0:d}"
SUB_INDENT = '    '
WIDETH = 30
class CItem(object):
    def __init__(self, name):
        self._name = name
        #raw data of the message string in the log
        #it's displayed in HEX format
        self._rawStr = '' 
        #display the additional information
        self._infoStr = '' 
        #display error information
        self._errStr = ''
        
        #the item has sub item
        #for example, message consist of element,
        #here message is item, element is subitem
        #use a dict to implement this list, the format is 
        #  itemName : item
        #so we can use the item name to find item
        self._subList = {}
        #as dict is not sorted, we use a name list to sort the item
        self._nameList = []

        self._indent = ''
        self._sepPos = WIDETH #The position where put seperator

    def SetIndent(self, indent):
        self._indent = indent
    def GetIndent(self):
        return self._indent
    def SetSepPos(self, pos):
        self._sepPos = pos
    def GetSepPos(self):
        return self._sepPos

    def FindSub(self, name):
        return self._subList[name]

    def FormDisplayString(self):
        if self._errStr != '' :
            self._errStr = "----Error:" + "(" + self._errStr + ")"
    
        if self._infoStr != '':
            self._infoStr = "(" + self._infoStr + ")"

        #display item information
        str = self._indent + ("{name:<"+"%d"%self._sepPos+"} : {raw} {info} {error}").format(name=self._name, raw=self._rawStr, info=self._infoStr, error=self._errStr)

        str = str + "\n"

    
        #display sub item information
        for name in self._nameList:
            if name in self._subList:
                subItem = self._subList[name]
                subItem.SetIndent(self.GetIndent() + SUB_INDENT)
                subItem.SetSepPos(self.GetSepPos() - len(SUB_INDENT))
                str = str + subItem.FormDisplayString()
            else:
                str = "The item is wrong\n"

        return str

    #use this function to initialize sub item list
    def InitSubItem(self):
        pass

    def Parse(self, dataStr):
        pass

class CHeader(CItem):
    _gName = "Header"
    def __init__(self, name = _gName):
        super(CHeader,self).__init__(name)
        self._headerLength = 0
        
        #the length indicated in header
        #it may include header, may not, depend on the protocol
        self._length = 0  

    def GetHeader(self):
        return self._rawStr

    def GetLength(self):
        return self._length

    def GetHeaderLength(self):
        return self._headerLength


class CAppHeader(CHeader):
    '''The application header'''
    _gName = "Application Header"

    #the sub item name
    _gNameAppId = "Application ID" 
    _gNameMsgType = "Message Type" 
    _gNameMsgCtrlFlag = "Message Control Flag" 
    _gNameMsgLen = "Message Length" 

    _gMaskAppId = 0x3F  # mask for application identifier
    _gMaskNonStdFlag = 0x40  # mask for non-standard flag in MsgType and AppId
    _gMaskTestFlag = 0x20    # mask for Test message flag
    _gMaskMsgType = 0x1F  # mask for message type
    _gMaskVersion = 0x70  # mask for version 
    _gMaskVersionFlag = 0x80 
    _gShiftVersionFlag = 7 
    _gShiftNonStdFlag = 6 
    _gShiftTestFlag = 5 
    _gMaskMoreFlag = 0x80 
    _gMaskMsgCtrlFlag = 0x0F  # mask for message control flag
    _gMask16BitMsgLength = 0x02  # mask for 16bit message length bit
    _gMaskResponseExpected = 0x01  # mask for response expected  
    _gMaskPriorityFlag = 0x03 
    _gShiftVersion = 4  # shift value for version
    _gMaskFirstMoreBit = 0x20  	# mask for first more-bit
    _gMaskMoreBit = 0x80  		# mask for all other more-bits 
    _gMaskFirstLength = 0x1F 		# mask for first length-value
    _gMaskLength = 0x7F 			# mask for all other length-values   
    _gMaxLengthOn8Bits = 0xFF

    def __init__(self,name=_gName):
        super(CAppHeader, self).__init__(name)

    def InitSubItem(self):
        name = self._gNameAppId
        item = CItem(name)
        self._subList[name] = item
        self._nameList.append(name)

        name = self._gNameMsgType
        item = CItem(name)
        self._subList[name] = item
        self._nameList.append(name)

        name = self._gNameMsgCtrlFlag
        item = CItem(name)
        self._subList[name] = item
        self._nameList.append(name)

        name = self._gNameMsgLen
        item = CItem(name)
        self._subList[name] = item
        self._nameList.append(name)

    def Parse(self, dataStr):
        #first initialize the sub item list
        self.InitSubItem()

        self._startIndex = dataStr.GetIndex()
        headerLength = 0

        #reading fisrt byte, save application ID
        value = dataStr.GetByte()
        headerLength = headerLength+1
        self._appId = value & self._gMaskAppId
        item = self._subList[self._gNameAppId]
        item._rawStr = DATA_FORMAT.format(self._appId)
        

        #reading second byte, save message type
        value = dataStr.GetByte()
        headerLength = headerLength+1
        self._nonStandardFlag = (value & self._gMaskNonStdFlag) >> self._gShiftNonStdFlag
        self._testFlag = (value & self._gMaskTestFlag) >> self._gShiftTestFlag
        self._msgType = value & self._gMaskMsgType
        item = self._subList[self._gNameMsgType]
        item._rawStr = DATA_FORMAT.format(self._msgType)

        #reading third byte, saving version
        value = dataStr.GetByte()
        headerLength=headerLength+1
        self._versionFlag = (value & self._gMaskVersionFlag) >> self._gShiftVersionFlag
        self._version = (value & self._gMaskVersion) >> self._gShiftVersion
        self._msgCtrlFlag = value & self._gMaskMsgCtrlFlag 
        item = self._subList[self._gNameMsgCtrlFlag]
        item._rawStr = HEX_DATA_FORMAT.format(self._msgCtrlFlag)

        # if there's a fourth byte with a priority flag, we save it
        if(self._versionFlag):
            value = dataStr.GetByte()
            headerLength=headerLength+1
            self._priority = value & self._gMaskPriorityFlag

        #reading  saving payload length and header length
        value = dataStr.GetByte()
        headerLength=headerLength+1
        if(self._msgCtrlFlag & self._gMask16BitMsgLength):
            #length bit is set, means it has 16bit length
            length = value << 8
            value = dataStr.GetByte()
            headerLength=headerLength+1
            length = length | value
        else:
            length = value
        self._length = length
        self._headerLength = headerLength

        item = self._subList[self._gNameMsgLen]
        item._rawStr = HEX_DATA_FORMAT.format(self._length)
        item._infoStr = DATA_FORMAT.format(self._length)

        self._rawStr = DATA_STRING_FORMAT.format(dataStr.GetString(self._startIndex, self._startIndex + headerLength))



        #end of parse()

class CEleHeader(CHeader):
    '''Header of information element'''
    _gName = "Element Header"

    _gMaskId = 0xC0 				# mask for identifier
    _gMaskFirstMoreBit = 0x20 	# mask for first more
    _gMaskMoreBit = 0x80 		# mask for all other more-
    _gMaskFirstLength = 0x1F		# mask for first length-
    _gMaskLength = 0x7F			# mask for all other length-v
    _gShiftId = 6 				# shift value for identi
    _gShiftFirstMoreBit = 5		# shift value for first mor
    _gShiftMoreBit = 7			# shift value for all other more-b
    _gMaxLengthOn5Bits = 0
    _gMaxLengthOn12Bits = 0x0FFF

    def __init__(self,name=_gName, recommendedLen = -1):
        super(CEleHeader, self).__init__(name)
        #if the recommendedLen is not -1, it means we should check the length value
        self._recommendedLen = recommendedLen


    def Parse(self, dataStr):
        self._startIndex = dataStr.GetIndex()
        headerLength = 0

        value = dataStr.GetByte()
        headerLength = headerLength+1
        self._id = value & self._gMaskId

        length = value & self._gMaskFirstLength
        if(value & self._gMaskFirstMoreBit):
            value = dataStr.GetByte()
            headerLength=headerLength+1
            length = length << 7
            length = length | (value & self._gMaskLength)
            if(value & self._gMaskMoreBit):
                value = dataStr.GetByte()
                headerLength=headerLength+1
                length = length << 7
                length = length | (value & self._gMaskLength)
        self._length = length
        self._headerLength = headerLength

        hdString = dataStr.GetString(self._startIndex, self._startIndex + headerLength)
        self._rawStr = DATA_STRING_FORMAT.format(hdString)
        self._infoStr = "length:" + DATA_FORMAT.format(self._length)

        if (self._recommendedLen != -1):
            if (self._recommendedLen != self._length):
                self._errStr = "Invalid length"


        #end of Parse()



class CStringItem(CItem):
    '''String item:
      This item include a header which indicates string length
      and a string
      its structure is similar like CInfoElement''' 
    _gName = "String Item"
    _gNameHeader = "Header"
    _gNameHex = "Hex"
    _gNameChar = "Char"

    def __init__(self,name=_gName, maxLen=-1):
        super(CStringItem, self).__init__(name)
        self._maxLen = maxLen

    def InitSubItem(self):
        name = self._gNameHeader
        item = CEleHeader(name)
        self._subList[name] = item
        self._nameList.append(name)

        name = self._gNameHex
        item = CItem(name)
        self._subList[name] = item
        self._nameList.append(name)

        name = self._gNameChar
        item = CItem(name)
        self._subList[name] = item
        self._nameList.append(name)

    def Parse(self, dataStr):
        #first initialize the sub item list
        self.InitSubItem()

        self._startIndex = dataStr.GetIndex()
        header = self._subList[self._gNameHeader]
        header.Parse(dataStr)

        len = header.GetLength()
        hLen = header.GetHeaderLength()

        if self._maxLen != -1:
            #this means set max len, so we should check it
            if len > self._maxLen:
                header._errStr = "Invalid length"

        string = dataStr.GetString(self._startIndex + hLen, self._startIndex + hLen + len)
        item = self._subList[self._gNameHex]
        item._rawStr = DATA_STRING_FORMAT.format(string)


        item = self._subList[self._gNameChar]
        cStr = ''
        for i in range(0,len):
            cStr = cStr + ("%c" % dataStr.GetByte())
        item._rawStr = "<" + STRING_FORMAT.format(cStr) + ">"


        #the raw data should include whole element string
        self._rawStr = DATA_STRING_FORMAT.format(dataStr.GetString(self._startIndex, self._startIndex + hLen + len))

        #end of parse()

class CInfoElement(CItem):
    '''information element:
       This is the base class of message element'''
    _gName = "Information Element"
    _gNameHeader = "Header"

    def __init__(self,name=_gName):
        super(CInfoElement, self).__init__(name)

    def InitSubItem(self):
        name = self._gNameHeader
        item = CEleHeader(name)
        self._subList[name] = item
        self._nameList.append(name)

    def ParseElement(self, dataStr):
        pass

    def Parse(self, dataStr):
        #first initialize the sub item list
        self.InitSubItem()

        self._startIndex = dataStr.GetIndex()
        header = self._subList[self._gNameHeader]
        header.Parse(dataStr)

        self.ParseElement(dataStr)

        #the raw data should include whole element string
        hLen=header.GetHeaderLength()
        len=header.GetLength()
        self._rawStr = DATA_STRING_FORMAT.format(dataStr.GetString(self._startIndex, self._startIndex + hLen + len))

        #end of parse()

class CVersionElement(CInfoElement):
    _gName = "Version Element"
    _gNameCarManId = "Car Manufacturer ID"
    _gNameDcmManId = "DCM Manufacturer ID"
    _gNameHwRel = "DCM Major HW"
    _gNameSwRel = "DCM Major SW"


    _gInfoLength = 4 #version element length is 4 byte(not include element header)
    _gCarManId = 0x0C
    _gDcmManId = 0x80
    _gHwRel = 0x01
    _gSwRel = 0x01

    def __init__(self, name=_gName):
        super(CVersionElement, self).__init__(name)

    def InitSubItem(self):
        name = self._gNameHeader
        item = CEleHeader(name, recommendedLen = self._gInfoLength)
        self._subList[name] = item
        self._nameList.append(name)

        name = self._gNameCarManId
        item = CItem(name)
        self._subList[name] = item
        self._nameList.append(name)

        name = self._gNameDcmManId
        item = CItem(name)
        self._subList[name] = item
        self._nameList.append(name)

        name = self._gNameHwRel
        item = CItem(name)
        self._subList[name] = item
        self._nameList.append(name)

        name = self._gNameSwRel
        item = CItem(name)
        self._subList[name] = item
        self._nameList.append(name)



    def ParseElement(self, dataStr):
        #version element has 4 byte item
        self._carManufacturerID = dataStr.GetByte()
        item = self._subList[self._gNameCarManId]
        item._rawStr = HEX_DATA_FORMAT.format(self._carManufacturerID)
        if self._carManufacturerID != self._gCarManId:
            item._errStr = "Invalid Car Manufacturer"

        self._dcmManufacturerID = dataStr.GetByte()
        item = self._subList[self._gNameDcmManId]
        item._rawStr = HEX_DATA_FORMAT.format(self._dcmManufacturerID)
        if self._dcmManufacturerID != self._gDcmManId:
            item._errStr = "Invalid DCM Manufacturer"

        self._hwRelease = dataStr.GetByte()
        item = self._subList[self._gNameHwRel]
        item._rawStr = HEX_DATA_FORMAT.format(self._hwRelease)
        if self._hwRelease != self._gHwRel:
            item._errStr = "Invalid HW Release"

        self._swRelease = dataStr.GetByte()
        item = self._subList[self._gNameSwRel]
        item._rawStr = HEX_DATA_FORMAT.format(self._swRelease)
        if self._swRelease != self._gSwRel:
            item._errStr = "Invalid SW Release"
        

class CVdFlag1(CItem):
    _gName = "vdFlag_1"
    _gNameVdf1AddFlag = "AddFlag"
    _gNameVdf1Language = "Language"
    _gNameVdf1Vin = "VIN"
    _gNameVdf1DcmId = "DCM_ID"
    _gNameVdf1NaviId = "NAVI_ID"
    _gNameVdf1ColModel = "Vehicle Color Model"
    _gNameVdf1Imei = "IMEI"

    _gAddFlag		= 0x80
    _gLanguageFlag	= 0x40
    _gVINFlag		= 0x20
    _gDCMFlag		= 0x10
    _gNaviFlag      = 0x08
    _gColoModelFlag = 0x06
    _gImeiFlag      = 0x01
    def __init__(self, name=_gName):
        super(CVdFlag1, self).__init__(name)
        self._vdFlag1 = 0
    
    def IsFlag2Present(self):
        return (self._vdFlag1 & self._gAddFlag) != 0

    def IsLanguagePresent(self):
        return (self._vdFlag1 & self._gLanguageFlag) != 0

    def IsVinPresent(self):
        return (self._vdFlag1 & self._gVINFlag) != 0

    def IsDcmIdPresent(self):
        return (self._vdFlag1 & self._gDCMFlag) != 0

    def IsNaviIdPresent(self):
        return (self._vdFlag1 & self._gNaviFlag) != 0

    def IsColoModelPresent(self):
        return (self._vdFlag1 & self._gColoModelFlag) != 0

    def IsImeiPresent(self):
        return (self._vdFlag1 & self._gImeiFlag) != 0

    def InitSubItem(self):
        name = self._gNameVdf1AddFlag
        self._subList[name] = CItem(name)
        self._nameList.append(name)

        name = self._gNameVdf1Language
        self._subList[name] = CItem(name)
        self._nameList.append(name)

        name = self._gNameVdf1Vin
        self._subList[name] = CItem(name)
        self._nameList.append(name)

        name = self._gNameVdf1DcmId
        self._subList[name] = CItem(name)
        self._nameList.append(name)

        name = self._gNameVdf1NaviId
        self._subList[name] = CItem(name)
        self._nameList.append(name)

        name = self._gNameVdf1ColModel
        self._subList[name] = CItem(name)
        self._nameList.append(name)

        name = self._gNameVdf1Imei
        self._subList[name] = CItem(name)
        self._nameList.append(name)

    def Parse(self, vdFlag):
        self.InitSubItem()

        self._vdFlag1 = vdFlag
        self._rawStr = HEX_DATA_FORMAT.format(vdFlag)

        item = self._subList[self._gNameVdf1AddFlag]
        if self.IsFlag2Present():
            f = 1
        else:
            f = 0
            item._errorStr = "Invalid value"
        item._rawStr = DATA_FORMAT.format(f)

        item = self._subList[self._gNameVdf1Language]
        if self.IsLanguagePresent():
            f = 1
            item._errorStr = "Invalid value"
        else:
            f = 0
        item._rawStr = DATA_FORMAT.format(f)

        item = self._subList[self._gNameVdf1Vin]
        if self.IsVinPresent():
            f = 1
            item._infoStr = "Present"
        else:
            f = 0
            item._infoStr = "Not Present"
        item._rawStr = DATA_FORMAT.format(f)

        item = self._subList[self._gNameVdf1DcmId]
        if self.IsDcmIdPresent():
            f = 1
            item._infoStr = "Present"
        else:
            f = 0
            item._infoStr = "Not Present"
        item._rawStr = DATA_FORMAT.format(f)

        item = self._subList[self._gNameVdf1NaviId]
        if self.IsNaviIdPresent():
            f = 1
            item._infoStr = "Present"
        else:
            f = 0
            item._infoStr = "Not Present"
        item._rawStr = DATA_FORMAT.format(f)

        item = self._subList[self._gNameVdf1ColModel]
        if self.IsColoModelPresent():
            f = 1
            item._errorStr = "Invalid value"
        else:
            f = 0
        item._rawStr = DATA_FORMAT.format(f)

        item = self._subList[self._gNameVdf1Imei]
        if self.IsImeiPresent():
            f = 1
            item._errorStr = "Invalid value"
        else:
            f = 0
        item._rawStr = DATA_FORMAT.format(f)

class CVdFlag2(CItem):
    _gName = "vdFlag_2"
    _gNameVdf2AddFlag = "AddFlag"
    _gNameVdf2ModelYear = "Model Year"
    _gNameVdf2AuthKey = "Authentication Key"
    _gNameVdf2IccId = "ICCID"
    _gNameVdf2Reserve = "Reserve"

    _gAddFlag		= 0x80
    _gYearFlag      = 0x40
    _gAuthKeyFlag   = 0x20
    _gIccidFlag     = 0x10
    _gReserveFlag   = 0x0F

    def __init__(self, name=_gName):
        super(CVdFlag2, self).__init__(name)
        self._vdFlag2 = 0

    def IsYearPresent(self):
        return (self._vdFlag2 & self._gYearFlag) != 0
    
    def IsAuthKeyPresent(self):
        return (self._vdFlag2 & self._gAuthKeyFlag) != 0
    
    def IsICCIdPresent(self):
        return (self._vdFlag2 & self._gIccidFlag) != 0

    def InitSubItem(self):
        name = self._gNameVdf2AddFlag
        self._subList[name] = CItem(name)
        self._nameList.append(name)

        name = self._gNameVdf2ModelYear
        self._subList[name] = CItem(name)
        self._nameList.append(name)

        name = self._gNameVdf2AuthKey
        self._subList[name] = CItem(name)
        self._nameList.append(name)

        name = self._gNameVdf2IccId
        self._subList[name] = CItem(name)
        self._nameList.append(name)

        name = self._gNameVdf2Reserve
        self._subList[name] = CItem(name)
        self._nameList.append(name)

    def Parse(self, vdFlag):
        self.InitSubItem()

        self._vdFlag2 = vdFlag
        self._rawStr = HEX_DATA_FORMAT.format(vdFlag)

        item = self._subList[self._gNameVdf2AddFlag]
        if ((self._vdFlag2 & self._gAddFlag) != 0):
            f = 1
            item._errorStr= "Invalid value"
        else:
            f = 0
        item._rawData = DATA_FORMAT.format(f)

        item = self._subList[self._gNameVdf2ModelYear]
        if self.IsYearPresent():
            f = 1
            item._errorStr = "Invalid value"
        else:
            f = 0
        item._rawStr = DATA_FORMAT.format(f)

        item = self._subList[self._gNameVdf2AuthKey]
        if self.IsAuthKeyPresent():
            f = 1
            item._errorStr = "Invalid value"
        else:
            f = 0
        item._rawStr = DATA_FORMAT.format(f)

        item = self._subList[self._gNameVdf2IccId]
        if self.IsICCIdPresent():
            f = 1
            item._infoStr = "Present"
        else:
            f = 0
            item._infoStr = "Not Present"
        item._rawStr = DATA_FORMAT.format(f)

        item = self._subList[self._gNameVdf2Reserve]
        if ((self._vdFlag2 & self._gReserveFlag) != 0):
            f = 1
            item._errorStr= "Invalid value"
        else:
            f = 0
        item._rawData = DATA_FORMAT.format(f)

class CVehicleDescriptorElement(CInfoElement):
    _gName = "Vehicle Descriptor"
    _gNameVdFlag1 = "vdFlag_1"

    _gNameVdFlag2 = "vdFlag_2"

    _gNameVin = "VIN"
    _gNameDcmId = "DCM ID"
    _gNameNaviId = "NAVI ID"
    _gNameIccId = "ICC ID"


    def __init__(self,name = _gName):
        super(CVehicleDescriptorElement, self).__init__(name)
        self._vdFlag1=0
        self._vdFlag2=0


    def InitSubItem(self):
        name = self._gNameHeader
        item = CEleHeader(name)
        self._subList[name] = item
        self._nameList.append(name)

        name = self._gNameVdFlag1
        item = CVdFlag1(name)
        self._subList[name] = item
        self._nameList.append(name)
    
        name = self._gNameVdFlag2
        item = CVdFlag2(name)
        self._subList[name] = item
        self._nameList.append(name)
    
        name = self._gNameVin
        item = CStringItem(name)
        self._subList[name] = item
        self._nameList.append(name)
    
        name = self._gNameDcmId
        item = CStringItem(name)
        self._subList[name] = item
        self._nameList.append(name)
    
        name = self._gNameNaviId
        item = CStringItem(name)
        self._subList[name] = item
        self._nameList.append(name)
    
        name = self._gNameIccId
        item = CStringItem(name)
        self._subList[name] = item
        self._nameList.append(name)
    


        
    def ParseElement(self, dataStr):
        self._vdFlag1 = dataStr.GetByte()
        vdFlag1Item = self._subList[self._gNameVdFlag1]
        vdFlag1Item.Parse(self._vdFlag1)
        

        vdFlag2Item = self._subList[self._gNameVdFlag2]
        if vdFlag1Item.IsFlag2Present():
            self._vdFlag2 = dataStr.GetByte()
            vdFlag2Item.Parse(self._vdFlag2)

        name = self._gNameVin
        item = self._subList[name]
        if vdFlag1Item.IsVinPresent():
            item.Parse(dataStr)
        else:
            del self._subList[name]

        name = self._gNameDcmId
        item = self._subList[name]
        if vdFlag1Item.IsDcmIdPresent():
            item.Parse(dataStr)
        else:
            del self._subList[name]

        name = self._gNameNaviId
        item = self._subList[name]
        if vdFlag1Item.IsNaviIdPresent():
            item.Parse(dataStr)
        else:
            del self._subList[name]

        name = self._gNameIccId
        item = self._subList[name]
        if vdFlag2Item.IsICCIdPresent():
            item.Parse(dataStr)
        else:
            del self._subList[name]

class CTimeElement(CItem):
    _gName = "Time Element"
    _gNameDate = "Date"
    _gNameTime = "Time"

    _gEleLength = 4
    def __init__(self, name=_gName):
        super(CTimeElement, self).__init__(name)

    def InitSubItem(self):
        name = self._gNameDate
        item = CItem(name)
        self._subList[name] = item
        self._nameList.append(name)

        name = self._gNameTime
        item = CItem(name)
        self._subList[name] = item
        self._nameList.append(name)

    def Parse(self, dataStr):
        self.InitSubItem()

        self._startIndex = dataStr.GetIndex()

        byte1 = dataStr.GetByte()
        byte2 = dataStr.GetByte()
        byte3 = dataStr.GetByte()
        byte4 = dataStr.GetByte()

        year = (byte1 >> 2) + 1990
        month = ((byte1 & 0x03) << 2) | ((byte2 & 0xC0) >> 6)
        day = (byte2 & 0x3E) >> 1
        hour = ((byte2 & 0x01) << 4) | ((byte3 & 0xF0) >> 4)
        min = ((byte3 & 0x0F) << 2) | ((byte4 & 0xC0) >> 6)
        sec = byte4 & 0x3F

        item = self._subList[self._gNameDate]
        item._rawStr = "{y:02d}-{m:02d}-{d:02d}".format(y=year, m=month, d=day)

        item = self._subList[self._gNameTime]
        item._rawStr = "{h:02d}:{m:02d}:{s:02d}".format(h=hour, m=min, s=sec)

        self._rawStr = DATA_STRING_FORMAT.format(dataStr.GetString(self._startIndex, self._startIndex + self._gEleLength))

class CControlFunctionElement(CInfoElement):
    _gName = "Control Function Element"
    _gNameCtrlFunc = "Control Function"
    _gNameParam1 = "Parameter_1"
    _gNameParam2 = "Parameter_2"

    _gEleLength = 3

    def __init__(self, name=_gName):
        super(CControlFunctionElement, self).__init__(name)

    def InitSubItem(self):
        name = self._gNameHeader
        item = CEleHeader(name, recommendedLen = self._gEleLength)
        self._subList[name] = item
        self._nameList.append(name)

        name = self._gNameCtrlFunc
        item = CItem(name)
        self._subList[name] = item
        self._nameList.append(name)

        name = self._gNameParam1
        item = CItem(name)
        self._subList[name] = item
        self._nameList.append(name)

        name = self._gNameParam2
        item = CItem(name)
        self._subList[name] = item
        self._nameList.append(name)

    #this function is implemented in child class
    #it's used to add more information about the function
    def AddInfo(self):
        pass

    def ParseElement(self, dataStr):
        self._function = dataStr.GetByte()
        item = self._subList[self._gNameCtrlFunc]
        item._rawStr = HEX_DATA_FORMAT.format(self._function)

        self._parameter1 = dataStr.GetByte()
        item = self._subList[self._gNameParam1]
        item._rawStr = HEX_DATA_FORMAT.format(self._function)

        self._parameter2 = dataStr.GetByte()
        item = self._subList[self._gNameParam2]
        item._rawStr = HEX_DATA_FORMAT.format(self._function)

        self.AddInfo()


if __name__ == "__main__":
    import Factory
    import DataString as ds
    #06033055040c800101030b00000302010001002040b810514a4e384844313653364b573333333333334c44434d4944363738393031324a4e4156494944373839305338393031363530393037303030343131323830
    #0602313b040c800101030b0000030301002028a010514a4e384844313653344b573531333030345338393031363530393037303036343433363637
    #0208314e040c800101000e000000a000000140002028a010514a4e384844313653364b5733333333333353383930313635303930373030303431313238300f00030c0100c80670df5e19d132d800
    dataStr = ds.CDataString("0208314e040c800101000e000000a000000140002028a010514a4e384844313653364b5733333333333353383930313635303930373030303431313238300f00030c0100c80670df5e19d132d800")

    header = CAppHeader()
    header.Parse(dataStr)
    str = header.FormDisplayString()
    print str

    item = CVersionElement()
    item.Parse(dataStr)
    str = item.FormDisplayString()
    print str

    item = CVehicleDescriptorElement()
    dataStr.SetIndex(20)
    item.Parse(dataStr)
    str = item.FormDisplayString()
    print str

    item = CTimeElement()
    dataStr.SetIndex(12)
    item.Parse(dataStr)
    str = item.FormDisplayString()
    print str
